package com.talkweb.baselibrary.banner;

import com.talkweb.baselibrary.ResourceTable;
import com.talkweb.baselibrary.banner.listener.OnItemClickListener;
import com.talkweb.baselibrary.banner.utils.ImageLoader;
import ohos.agp.components.*;
import ohos.agp.utils.LayoutAlignment;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.multimodalinput.event.TouchEvent;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import static ohos.agp.components.ComponentContainer.LayoutConfig.MATCH_CONTENT;
import static ohos.agp.components.ComponentContainer.LayoutConfig.MATCH_PARENT;
import static ohos.multimodalinput.event.TouchEvent.*;

/**
 * 页面翻转控件，极方便的广告栏
 * 支持无限循环，自动翻页，翻页特效
 *
 * @author Sai 支持自动翻页
 */
public class ConvenientBanner extends StackLayout implements PageSlider.PageChangedListener, Component.TouchEventListener {
    private static final int DEFAULT_START_INDEX = -9527;
    private List<?> mDatas;
    private int[] page_indicatorId;
    private ArrayList<Image> mPointViews = new ArrayList<Image>();
    private BannerPagerAdapter pageAdapter;
    private PageSlider viewPager;
    private DirectionalLayout loPageTurningPoint;
    private long autoTurningTime = -1;
    private boolean turning;
    private boolean canTurn = false;
    private boolean canLoop = true;
    private AdSwitchTask adSwitchTask;
    private boolean isVertical = false;
    private List<Component> imageViews;
    private Context context;
    private OnItemClickListener listener;
    private EventRunner runner = EventRunner.current();
    private EventHandler handler = new EventHandler(runner);

    private boolean smoothScroll;
    private Image.ScaleMode scaleMode = Image.ScaleMode.STRETCH;
    private int count;
    private int currentItem;
    private int lastPosition;
    private int startIndex = DEFAULT_START_INDEX;

    public enum PageIndicatorAlign {
        ALIGN_PARENT_LEFT, ALIGN_PARENT_RIGHT, CENTER_HORIZONTAL
    }

    public ConvenientBanner(Context context) {
        super(context);
        init(context);
    }

    public ConvenientBanner(Context context, AttrSet attrs) {
        super(context, attrs);
        Optional<Attr> loopOptional = attrs.getAttr("canLoop");
        if (loopOptional.isPresent()) {
            canLoop = loopOptional.get().getBoolValue();
            if (canLoop) {
                currentItem = 1;
                lastPosition = 1;
            }
        }
        Optional<Attr> autoTurningTimeOptional = attrs.getAttr("autoTurningTime");
        if (autoTurningTimeOptional.isPresent()) {
            autoTurningTime = autoTurningTimeOptional.get().getIntegerValue();
        }
        init(context);
    }

    private void init(Context context) {
        this.context = context;
        imageViews = new ArrayList<>();
        page_indicatorId = new int[]{ResourceTable.Media_ic_page_indicator, ResourceTable.Media_ic_page_indicator_focused};
        Component component = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_include_viewpager, this, true);
        viewPager = (PageSlider) component.findComponentById(ResourceTable.Id_bannerViewPager);
        loPageTurningPoint = (DirectionalLayout) component.findComponentById(ResourceTable.Id_circleIndicator);
        loPageTurningPoint.setAlignment(LayoutAlignment.CENTER);
        adSwitchTask = new AdSwitchTask(this);
        setTouchEventListener(this);
    }

    public ConvenientBanner setPages(List<?> datas) {
        if (datas == null)
            return this;
        this.mDatas = datas;
        this.count = datas.size();
        return this;
    }

    public void start() {
        if (page_indicatorId != null)
            setPageIndicator(page_indicatorId);
        if (mDatas == null) {
            return;
        }
        setImageList(mDatas);
        setData();
    }

    public ConvenientBanner setCanLoop(boolean canLoop){
        this.canLoop = canLoop;
        if (canLoop) {
            currentItem = 1;
            lastPosition = 1;
        } else {
            currentItem = 0;
            lastPosition = 0;
        }
        notifyDataSetChanged();
        return this;
    }

    public boolean isCanLoop(){
        return canLoop;
    }

    /**
     * 通知数据变化
     */
    public void notifyDataSetChanged() {
        if (pageAdapter != null) {
            pageAdapter.notifyDataChanged();
        }
        if (page_indicatorId != null)
            setPageIndicator(page_indicatorId);
        viewPager.setCurrentPage(canLoop ? 1 : 0);
        if (canLoop) {
            startTurning();
        }
    }

    /**
     * 设置底部指示器是否可见
     *
     * @param visible
     */
    public ConvenientBanner setPointViewVisible(boolean visible) {
        loPageTurningPoint.setVisibility(visible ? VISIBLE : HIDE);
        return this;
    }

    /**
     * 底部指示器资源图片
     *
     * @param page_indicatorId
     */
    public ConvenientBanner setPageIndicator(int[] page_indicatorId) {
        loPageTurningPoint.removeAllComponents();
        mPointViews.clear();
        this.page_indicatorId = page_indicatorId;
        if (mDatas == null) return this;
        for (int i = 0; i < count; i++) {
            Image pointView = new Image(context);
            DirectionalLayout.LayoutConfig params;
            if (i == currentItem && !canLoop) {
                params = new DirectionalLayout.LayoutConfig(MATCH_CONTENT, MATCH_CONTENT);
                pointView.setPixelMap(page_indicatorId[1]);
            } else if (i == currentItem - 1 && canLoop) {
                params = new DirectionalLayout.LayoutConfig(MATCH_CONTENT, MATCH_CONTENT);
                pointView.setPixelMap(page_indicatorId[1]);
            } else {
                params = new DirectionalLayout.LayoutConfig(MATCH_CONTENT, MATCH_CONTENT);
                pointView.setPixelMap(page_indicatorId[0]);
            }
            params.setMargins(10, 0, 10, 0);
            mPointViews.add(pointView);
            loPageTurningPoint.addComponent(pointView, params);
        }
        return this;
    }

    /**
     * 监听item点击
     *
     * @param onItemClickListener
     */
    public ConvenientBanner setOnItemClickListener(final OnItemClickListener onItemClickListener) {
        this.listener = onItemClickListener;
        return this;
    }

    /**
     * 获取当前页对应的position
     * @return
     */
    public int getCurrentItem() {
        if (canLoop) {
            return getRealPosition(currentItem);
        }
        return currentItem;
    }

    /**
     * 设置当前页对应的position
     * @return
     */
    public ConvenientBanner setCurrentItem(int position, boolean smoothScroll) {
        this.startIndex = position;
        this.smoothScroll = smoothScroll;
        return this;
    }

    private void calculate(int position) {
         if (canLoop) {
            if (position >= count) {
                currentItem = count;
                if (count == 1) {
                    lastPosition = 0;
                }
                lastPosition = currentItem - 1;
            } else if (position <= 0) {
                currentItem = 1;
                lastPosition = 0;
            } else {
                currentItem = position + 1;
                lastPosition = currentItem - 1;
            }
        } else {
            if (position >= count) {
                currentItem = count - 1;
                if (count == 1) {
                    lastPosition = 0;
                } else {
                    lastPosition = currentItem - 1;
                }
            } else if (position <= 0) {
                currentItem = 0;
                lastPosition = 0;
            } else {
                currentItem = position;
                lastPosition = currentItem - 1;
            }
        }
    }

    public ConvenientBanner setFirstItemPosition(int position) {
        calculate(position);
        return this;
    }

    public ConvenientBanner setPageIndicatorAlign(PageIndicatorAlign align) {
        switch (align) {
            case ALIGN_PARENT_LEFT:
                loPageTurningPoint.setAlignment(LayoutAlignment.LEFT | LayoutAlignment.VERTICAL_CENTER);
                break;
            case ALIGN_PARENT_RIGHT:
                loPageTurningPoint.setAlignment(LayoutAlignment.RIGHT | LayoutAlignment.VERTICAL_CENTER);
                break;
            case CENTER_HORIZONTAL:
                loPageTurningPoint.setAlignment(LayoutAlignment.CENTER);
                break;
        }
        return this;
    }

    /***
     * 是否开启了翻页
     * @return
     */
    public boolean isTurning() {
        return turning;
    }

    /***
     * 开始翻页
     * @param autoTurningTime 自动翻页时间
     * @return
     */
    public ConvenientBanner startTurning(long autoTurningTime) {
        if (autoTurningTime < 0) return this;
        if (!canLoop) {
            return this;
        }
        //如果是正在翻页的话先停掉
        if (turning) {
            stopTurning();
        }
        //设置可以翻页并开启翻页
        canTurn = true;
        this.autoTurningTime = autoTurningTime;
        turning = true;
        handler.postTask(adSwitchTask, autoTurningTime);
        return this;
    }

    public ConvenientBanner startTurning() {
        startTurning(autoTurningTime);
        return this;
    }


    public void stopTurning() {
        turning = false;
        handler.removeTask(adSwitchTask);
    }

    private void setImageList(List<?> imagesUrl) {
        imageViews.clear();
        if (canLoop && count > 1) {
            for (int i = 0; i <= count + 1; i++) {
                Object url = null;
                if (i == 0) {
                    url = imagesUrl.get(count - 1);
                } else if (i == count + 1) {
                    url = imagesUrl.get(0);
                } else {
                    url = imagesUrl.get(i - 1);
                }
                loadImage(url);
            }
        } else {
            for (int i = 0; i < count; i++) {
                Object url = imagesUrl.get(i);
                loadImage(url);
            }
        }
    }

    private void loadImage(Object url) {
        if (url instanceof String) {
            Image imageView = ImageLoader.createImageView(context, (String) url);
            imageView.setScaleMode(scaleMode);
            imageViews.add(imageView);
        } else if (url instanceof Integer) {
            Image image = new Image(context);
            image.setScaleMode(scaleMode);
            image.setPixelMap((Integer) url);
            image.setLayoutConfig(new DirectionalLayout.LayoutConfig(MATCH_PARENT, MATCH_PARENT));
            imageViews.add(image);
        }
    }

    private void setData() {
        if (startIndex != DEFAULT_START_INDEX) {
            calculate(startIndex);
        }
        if (pageAdapter == null) {
            pageAdapter = new BannerPagerAdapter();
            viewPager.addPageChangedListener(this);
            viewPager.setProvider(pageAdapter);
        } else {
            pageAdapter.notifyDataChanged();
        }
        viewPager.setCurrentPage(currentItem, smoothScroll);
    }

    public ConvenientBanner setScaleMode(Image.ScaleMode scaleMode) {
        this.scaleMode = scaleMode;
        return this;
    }

    private int getRealPosition(int position) {
        int realPosition = 0;
        if (count != 0) {
            realPosition = (position - 1) % count;
        }
        if (realPosition < 0)
            realPosition += count;
        return realPosition;
    }

    @Override
    public void onPageSliding(int position, float positionOffset, int positionOffsetPixels) {
    }

    @Override
    public void onPageSlideStateChanged(int state) {
        if (canLoop && count > 1) {
            switch (state) {
                case 0://No operation
                    if (currentItem == 0) {
                        viewPager.setCurrentPage(count, false);
                    } else if (currentItem == count + 1) {
                        viewPager.setCurrentPage(1, false);
                    }
                    break;
                case 1://start Sliding
                    if (currentItem == count + 1) {
                        viewPager.setCurrentPage(1, false);
                    } else if (currentItem == 0) {
                        viewPager.setCurrentPage(count, false);
                    }
                    break;
                case 2://end Sliding
                    break;
            }
        }
    }

    @Override
    public void onPageChosen(int position) {
        currentItem = position;
        if (mPointViews.isEmpty()) {
            return;
        }
        if (canLoop) {
            mPointViews.get((lastPosition - 1 + count) % count).setPixelMap(page_indicatorId[0]);
            mPointViews.get((position - 1 + count) % count).setPixelMap(page_indicatorId[1]);
            lastPosition = position;
        } else {
            mPointViews.get(lastPosition).setPixelMap(page_indicatorId[0]);
            mPointViews.get(position).setPixelMap(page_indicatorId[1]);
            lastPosition = position;
        }
    }

    class BannerPagerAdapter extends PageSliderProvider {
        @Override
        public int getCount() {
            return imageViews.size();
        }

        @Override
        public Object createPageInContainer(ComponentContainer container, final int position) {
            container.addComponent(imageViews.get(position));
            Component view = imageViews.get(position);
            if (listener != null) {
                view.setClickedListener(new ClickedListener() {
                    @Override
                    public void onClick(Component v) {
                        if (canLoop) {
                            listener.onItemClick(getRealPosition(position));
                        } else {
                            listener.onItemClick(position);
                        }
                    }
                });
            }
            return view;
        }

        @Override
        public void destroyPageFromContainer(ComponentContainer componentContainer, int position, Object o) {
            componentContainer.removeComponent((Component) o);
        }

        @Override
        public boolean isPageMatchToObject(Component component, Object o) {
            return component == o;
        }
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        int action = touchEvent.getAction();
        if (action == PRIMARY_POINT_UP || action == CANCEL
                || action == NONE) {
            // 开始翻页
            if (canTurn) startTurning(autoTurningTime);
        } else if (action == PRIMARY_POINT_DOWN) {
            // 停止翻页
            if (canTurn) stopTurning();
        }
        return true;
    }

    static class AdSwitchTask implements Runnable {
        private final WeakReference<ConvenientBanner> reference;

        AdSwitchTask(ConvenientBanner convenientBanner) {
            this.reference = new WeakReference<ConvenientBanner>(convenientBanner);
        }

        @Override
        public void run() {
            ConvenientBanner convenientBanner = reference.get();
            if (convenientBanner != null) {
                if (convenientBanner.count > 1 && convenientBanner.turning) {
                    convenientBanner.currentItem = convenientBanner.currentItem % (convenientBanner.count + 1) + 1;
                    convenientBanner.viewPager.setCurrentPage(convenientBanner.currentItem, true);
                    convenientBanner.handler.postTask(convenientBanner.adSwitchTask, convenientBanner.autoTurningTime);
                }
            }
        }
    }
}